package references

import (
	"jvm/nzpJvm/instructions/base"
	"jvm/nzpJvm/runtime_area"
	"jvm/nzpJvm/runtime_area/heap"
)

type GET_FIELD struct{ base.Index16Instruction }

// getfield需要两个操作数，第一个16字节，可以在常量池定位到一个字段的符号引用，来自字节码
// 第二个从操作数栈弹出，代表一个对象的引用
func (self *GET_FIELD) Execute(frame *runtime_area.Frame) {
	// 获取当前类的运行时常量池
	currentMethod := frame.Method()
	currentClass := currentMethod.Class()
	constantPool := currentClass.ConstantPool()
	// 从常量池获取字段的符号引用
	fieldRef := constantPool.GetConstant(self.Index).(*heap.FieldRef)
	// 根据符号引用获取直接引用
	field := fieldRef.ResolveField()

	// 如果这个字段是静态字段，抛出异常
	if field.IsStatic() {
		panic("java.lang.IncompatibleClassChangeError")
	}

	descriptor:= field.Descriptor()
	slotId := field.SlotId()
	stack := frame.OperandStack()

	object := stack.PopRef()
	if object == nil {
		panic("java.lang.NullPointerException")
	}
	fields := object.Fields()

	switch descriptor[0] {
	case 'Z', 'B', 'C', 'S', 'I':
		// boolean，byte，char，short，int都当做int来处理
		value := fields.GetInt(slotId)
		stack.PushInt(value)
	case 'J':
		// long
		value := fields.GetLong(slotId)
		stack.PushLong(value)
	case 'F':
		// float
		value := fields.GetFloat(slotId)
		stack.PushFloat(value)
	case 'D':
		// double
		value := fields.GetDouble(slotId)
		stack.PushDouble(value)
	case 'L','[':
		// 引用类型和数组类型，描述符是不一样的，L和[
		value := fields.GetRef(slotId)
		stack.PushRef(value)
	}
}
